package com.hd.service.activiti.impl;
import com.hd.commons.exception.MyException;
import com.hd.dao.BaseDao;
import com.hd.entity.activiti.ElementDef;
import com.hd.entity.activiti.UserTaskInfo;
import com.hd.entity.sys.User;
import com.hd.service.activiti.ElementDefService;
import com.hd.service.activiti.SqlConditionService;
import com.hd.service.activiti.UserTaskInfoService;
import com.hd.service.activiti.UserTaskService;
import com.hd.service.sys.UserService;
import com.hd.util.BeanUtils;
import com.hd.util.JsonUtil;
import com.hd.util.StringUtils;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
 * 操作节点定义
 */
@Service("elementDefService")
public class ElementDefServiceImpl implements ElementDefService {
	private static final Logger log= LoggerFactory.getLogger(ElementDefServiceImpl.class);
	@Autowired
	private BaseDao<ElementDef,String>elementDefDao;
	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private ProcessEngine processEngine;
	@Autowired
	private UserTaskInfoService userTaskInfoService;
	@Autowired
	private UserTaskService userTaskService;
	@Autowired
	private SqlConditionService sqlConditionService;
	@Autowired
	private UserService userService;
	@Override
	public void save(ElementDef elementDef) {
		elementDef.setId(UUID.randomUUID().toString());
		elementDefDao.save(elementDef);
	}

	/**
	 * 查询一条数据
	 * @param id
	 * @return
	 */
	@Override
	public ElementDef get(String id) {
		return elementDefDao.get(ElementDef.class,id);
	}

	/**
	 * 初始化节点
	 */
	@Override
	public void init(String procdefId) {
		BpmnModel model = repositoryService.getBpmnModel(procdefId);
		if(model != null) {
			 int i=1;
		    Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
		    for(FlowElement e : flowElements) {
		        System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().getName());
		        if(e.getClass().getName().toString().equals("org.activiti.bpmn.model.StartEvent")) {
		        	ElementDef vo = findByParams(procdefId,e.getId());
		        	System.out.println("procdefId="+procdefId);
		        	System.out.println("key:"+e.getId());
		        	System.out.println(vo==null);
		        	if(vo==null) {
			        	ElementDef elementDef=new ElementDef();
			        	elementDef.setProcdefId(procdefId);
			        	elementDef.setName(e.getName());
			        	elementDef.setKey(e.getId());
			        	elementDef.setElementType("StartEvent");
			        	elementDef.setSeq(i);
						elementDef.setPrint(false);
			        	save(elementDef);
		        	}else {
		        		vo.setName(e.getName());
		        		elementDefDao.update(vo);
		        	}
		        }
		        if(e.getClass().getName().toString().equals("org.activiti.bpmn.model.UserTask")) {
		        	ElementDef vo = findByParams(procdefId,e.getId());
		        	if(vo==null) {
			        	ElementDef elementDef=new ElementDef();
			        	elementDef.setProcdefId(procdefId);
			        	elementDef.setName(e.getName());
			        	elementDef.setKey(e.getId());
			        	elementDef.setElementType("UserTask");
			        	elementDef.setSeq(i);
						elementDef.setPrint(true);
			        	save(elementDef);
		        	}else {
		        		vo.setName(e.getName());
		        		elementDefDao.update(vo);
		        	}
		        }
		        if(e.getClass().getName().toString().equals("org.activiti.bpmn.model.EndEvent")) {
		        	ElementDef vo = findByParams(procdefId,e.getId());
		        	if(vo==null) {
			        	ElementDef elementDef=new ElementDef();
			        	elementDef.setProcdefId(procdefId);
			        	elementDef.setName(e.getName());
			        	elementDef.setKey(e.getId());
			        	elementDef.setElementType("EndEvent");
						elementDef.setPrint(false);
			        	elementDef.setSeq(i);
			        	save(elementDef);
		        	}else {
		        		vo.setName(e.getName());
		        		elementDefDao.update(vo);
		        	}
		        }
		        i++;
		    }
		}

	}
	@Override
	public ElementDef findByParams(String procdefId,String key) {
		String hql="from ElementDef where procdefId=? and key=?";
		List<ElementDef> elementDefs = elementDefDao.find(hql, procdefId,key);
		if(elementDefs.size()>0) {
			return elementDefs.get(0);
		}
		return null;
	}
	@Override
	public void delete(String id) {
		elementDefDao.delete(ElementDef.class, id);
	}

	@Override
	public void update(ElementDef elementDef) {
		elementDefDao.update(elementDef);
	}



	@Override
	public List<ElementDef> find(String procdefId) {
		String hql="from ElementDef where procdefId=? order by seq asc";
		List<ElementDef> elementDefs = elementDefDao.find(hql, procdefId);
		return elementDefs;
	}

	@Override
	public ElementDef getStartElement(String procdefId) {
		String hql="from ElementDef where procdefId=? and elementType='StartEvent'";
		List<ElementDef> elementDefs = elementDefDao.find(hql, procdefId);
		if(elementDefs.size()>0) {
			return elementDefs.get(0);
		}
		return null;
	}

	/**
	 * 下一个之后的所有节点集合
	 */
	@Override
	public List<ElementDef> getNextElementDefs(String procdefId, String key) {
		System.out.println("procdefId="+procdefId);
		ElementDef elementDef = findByParams(procdefId, key);
		String hql="from ElementDef where seq>? and procdefId=? order by seq asc";
		List<ElementDef> elementDefs = elementDefDao.find(hql, elementDef.getSeq(),procdefId);
		return elementDefs;
	}

	/**
	 * 前一个节点之前的所有节点集合
	 */
	@Override
	public List<ElementDef> getPrevElementDefs(String procdefId, String key) {
		ElementDef elementDef = findByParams(procdefId, key);
		String hql="from ElementDef where seq<? and procdefId=? order by seq asc";
		List<ElementDef> elementDefs = elementDefDao.find(hql, elementDef.getSeq(),procdefId);
		return elementDefs;
	}
	
	
	/**
	 * @date 2018/3/23 16:41
	 * @title getNextNode
	 * @description: 获取下一步用户任务节点
	 * @param procDefId     流程定义ID
	 * @param taskDefKey    当前任务KEY
	 * @param map           业务数据
	 * @return: java.util.List<org.activiti.bpmn.model.UserTask>
	 */
	@Override
	public List<UserTask> getNextNode(String procDefId, String taskDefKey, Map<String, Object> map) {
		List<UserTask> userTasks = new ArrayList<>();
		//获取BpmnModel对象
		BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(procDefId);
		//获取Process对象
		Process process = bpmnModel.getProcesses().get(bpmnModel.getProcesses().size()-1);
		//获取所有的FlowElement信息
		Collection<FlowElement> flowElements = process.getFlowElements();
		//获取当前节点信息
		FlowElement flowElement = getFlowElementById(taskDefKey,flowElements);

		getNextNode(flowElements,flowElement,map,userTasks);

		return userTasks;
	}

	/**
	 * @date 2018/4/11 9:52
	 * @title getNextNode
	 * @description: 查询下一步节点
	 * @param flowElements  全流程节点集合
	 * @param flowElement   当前节点
	 * @param map           业务数据
	 * @param nextUser      下一步用户节点
	 * @return: void
	 */
	private void getNextNode(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map,List<UserTask> nextUser){

		//如果是结束节点
		if(flowElement instanceof EndEvent){
			//如果是子任务的结束节点
			if(getSubProcess(flowElements,flowElement) != null){
				flowElement = getSubProcess(flowElements,flowElement);
			}
		}

		//获取Task的出线信息--可以拥有多个
		List<SequenceFlow> outGoingFlows = null;
		if(flowElement instanceof Task){
			outGoingFlows = ((Task) flowElement).getOutgoingFlows();
		}else if(flowElement instanceof Gateway){
			outGoingFlows = ((Gateway) flowElement).getOutgoingFlows();
		}else if(flowElement instanceof StartEvent){
			outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows();
		}else if(flowElement instanceof SubProcess){
			outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows();
		}

		if(outGoingFlows != null && outGoingFlows.size()>0) {
			//遍历所有的出线--找到可以正确执行的那一条
			for (SequenceFlow sequenceFlow : outGoingFlows) {

				//1.有表达式，且为true
				//2.无表达式
				String expression = sequenceFlow.getConditionExpression();
				System.out.println(expression);
				boolean b=true;
				if(!map.isEmpty()) {
					List<String>keys=new ArrayList<String>();
					List<String>values=new ArrayList<String>();
					for (Map.Entry<String, Object> entry : map.entrySet()) { 
						keys.add(entry.getKey());
						values.add(entry.getValue().toString());
						System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 
					}
					if(StringUtils.isNotNull(expression)) {
						b=isConditionEl(keys, expression, values);
					}
				}
				
				if(StringUtils.isNull(expression)||b){
					//出线的下一节点
					String nextFlowElementID = sequenceFlow.getTargetRef();
					//查询下一节点的信息
					FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements);

					//用户任务
					if (nextFlowElement instanceof UserTask) {
						nextUser.add((UserTask) nextFlowElement);
					}
					//排他网关
					else if (nextFlowElement instanceof ExclusiveGateway) {
						getNextNode(flowElements, nextFlowElement, map, nextUser);
					}
					//并行网关
					else if (nextFlowElement instanceof ParallelGateway) {
						getNextNode(flowElements, nextFlowElement, map, nextUser);
					}
					//接收任务
					else if (nextFlowElement instanceof ReceiveTask) {
						getNextNode(flowElements, nextFlowElement, map, nextUser);
					}
					//子任务的起点
					else if(nextFlowElement instanceof StartEvent){
						getNextNode(flowElements, nextFlowElement, map, nextUser);
					}
					//结束节点
					else if(nextFlowElement instanceof EndEvent){
						getNextNode(flowElements, nextFlowElement, map, nextUser);
					}
				}
			}
		}
	}
	/**
	 * @date 2018/4/11 9:44
	 * @title getSubProcess
	 * @description: 查询一个节点的是否子任务中的节点，如果是，返回子任务
	 * @param flowElements 全流程的节点集合
	 * @param flowElement   当前节点
	 * @return: org.activiti.bpmn.model.FlowElement
	 */
	private FlowElement getSubProcess(Collection<FlowElement> flowElements,FlowElement flowElement){
		for(FlowElement flowElement1 : flowElements){
			if(flowElement1 instanceof SubProcess){
				for(FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()){
					if(flowElement.equals(flowElement2)){
						return flowElement1;
					}
				}
			}
		}
		return null;
	}


	/**
	 * @date 2018/3/23 16:43
	 * @title getFlowElementById
	 * @description: 根据ID查询流程节点对象,如果是子任务，则返回子任务的开始节点
	 * @param Id            节点ID
	 * @param flowElements  流程节点集合
	 * @return: org.activiti.bpmn.model.FlowElement
	 */
	private FlowElement getFlowElementById(String Id,Collection<FlowElement> flowElements){
		for(FlowElement flowElement : flowElements){
			if(flowElement.getId().equals(Id)){
				//如果是子任务，则查询出子任务的开始节点
				if(flowElement instanceof SubProcess){
					return getStartFlowElement(((SubProcess) flowElement).getFlowElements());
				}
				return flowElement;
			}
			if(flowElement instanceof SubProcess){
				FlowElement flowElement1 = getFlowElementById(Id,((SubProcess) flowElement).getFlowElements());
				if(flowElement1 != null){
					return flowElement1;
				}
			}
		}
		return null;
	}

	/**
	 * @date 2018/4/10 15:57
	 * @title getStartFlowElement
	 * @description: 返回流程的开始节点
	 * @param flowElements
	 * @return: org.activiti.bpmn.model.FlowElement
	 */
	private FlowElement getStartFlowElement(Collection<FlowElement> flowElements){
		for (FlowElement flowElement :flowElements){
			if(flowElement instanceof StartEvent){
				return flowElement;
			}
		}
		return null;
	}
	/**
	 * 判断JUEL表达式是否通过
	 * @param keys
	 * @param el
	 * @param values
	 * @return
	 */
	public boolean isConditionEl(List<String> keys, String el, List<String> values) {
		ExpressionFactory factory = new ExpressionFactoryImpl();
		SimpleContext context = new SimpleContext();
		for(int i=0;i<keys.size();i++) {
			context.setVariable(keys.get(i), factory.createValueExpression(values.get(i), String.class));
		}
		ValueExpression e = factory.createValueExpression(context, el, boolean.class);
		return (Boolean) e.getValue(context);
	}

	/**
	 * 获取下一节点信息
	 */
	@Override
	public List<com.hd.entity.activiti.UserTask> getNextTaskNode(String procDefId,String procDefKey, String startKey,
			Map<String, Object> map, String objId,String userid) {
		List<com.hd.entity.activiti.UserTask>tasks=new ArrayList<com.hd.entity.activiti.UserTask>();
		if(StringUtils.isNull(procDefId)) {
			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).latestVersion().singleResult();
			procDefId = processDefinition.getId();
		}
		List<UserTask>userTasks=getNextNode(procDefId,startKey,map);
		for (int i=0;i<userTasks.size();i++){
			String taskDefKey=userTasks.get(i).getId();
			com.hd.entity.activiti.UserTask task = userTaskService.getUserTaskByParams(procDefId, taskDefKey);
			log.info("procDefId={},taskDefKey={}",procDefId,taskDefKey);
			com.hd.entity.activiti.UserTask task1=new com.hd.entity.activiti.UserTask();
			if(StringUtils.isNotNull(task)) {
				BeanUtils.copyProperties(task, task1);
				//设置任务执行人
				if (StringUtils.isNotNull(task.getSelectModel())) {
					if (task.getSelectModel().equals(com.hd.entity.activiti.UserTask.SUPERIOR)) {
						//前一步直接上级
						User user = sqlConditionService.getPrevSuperior(userid);
						if (user != null) {
							task1.setCandidate_ids(user.getId());
							task1.setCandidate_name(user.getName());
						}
					}
					if (task.getSelectModel().equals(com.hd.entity.activiti.UserTask.POSITION)) {
						//指定职位
						if (StringUtils.isNotNull(task.getConditionId())) {
							List<User> users = sqlConditionService.getByPositionId(task.getConditionId());
							if (users.size() > 0) {
								if (StringUtils.isNotNull(task.getTaskType())) {
									if (task.getTaskType().equals("candidateUser")) {
										String userIds = "";
										String userNames = "";
										for (User user : users) {
											userIds += user.getId();
											userNames += user.getName();
										}
										userIds = userIds.substring(0, userIds.lastIndexOf(","));
										userNames = userNames.substring(0, userNames.lastIndexOf(","));
										task1.setCandidate_ids(userIds);
										task1.setCandidate_name(userNames);
									}
									if (task.getTaskType().equals("assignee")) {
										task1.setCandidate_ids(users.get(0).getId());
										task1.setCandidate_name(users.get(0).getName());
									}
								} else {
									task1.setTaskType("candidateUser");
								}
							}
						}

					}
				}


				/**
				 * 设置默认模式为候选人
				 */
				if (StringUtils.isNull(task.getTaskType())) {
					task1.setTaskType("candidateUser");
				} else {
					if (task.getTaskType().equals("candidateGroup")) {
						task1.setTaskType("candidateUser");
						if (StringUtils.isNotNull(task.getCandidate_ids())) {
							List<User> users = userService.findByRoleIds(task.getCandidate_ids());
							String userIds = "";
							String userNames = "";
							if (users.size() > 0) {
								for (User user : users) {
									userIds += user.getId() + ",";
									userNames += user.getName() + ",";
								}
								userIds = userIds.substring(0, userIds.lastIndexOf(","));
								userNames = userNames.substring(0, userNames.lastIndexOf(","));
							}
							task1.setCandidate_ids(userIds);
							task1.setCandidate_name(userNames);
						}
					}
				}
				if (StringUtils.isNotNull(objId)) {
					UserTaskInfo info = userTaskInfoService.getByParams(procDefId, taskDefKey, objId);
					System.out.println(JsonUtil.toJson(info));
					if (info != null) {
						task1.setCandidate_ids(info.getUserids());
						task1.setCandidate_name(info.getUserNames());
					}
				}
				if(StringUtils.isNull(task1.getCandidate_ids())){
					task1.setCandidate_ids("");
					task1.setCandidate_name("");
				}
				tasks.add(task1);
			}else{
				throw new MyException("流程任务设置有误！请在流程部署中设置任务节点！");
			}
		}
		return tasks;
	}

	/**
	 * 保存下一步节点任务执行人
	 */
	@Override
	public void setNextNodeAssignees(String procDefKey, String startKey, String objId, Map<String, Object> map,
			HttpServletRequest request) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).latestVersion().singleResult();
		String procDefId=processDefinition.getId();
		List<UserTask>userTasks=getNextNode(procDefId,startKey,map);
		for (int i=0;i<userTasks.size();i++){
			String taskDefKey=userTasks.get(i).getId();
			String taskName=userTasks.get(i).getName();
			//保存任务执行人
			UserTaskInfo userTaskInfo=new UserTaskInfo();
			userTaskInfo.setProcDefId(procDefId);
			userTaskInfo.setTaskDefKey(taskDefKey);
			userTaskInfo.setTaskName(taskName);
			Long frequency=1L;
			UserTaskInfo vo=userTaskInfoService.getByParams(procDefId, taskDefKey, objId);
			if(vo!=null) {
				frequency=vo.getFrequency()+1L;
			}
			userTaskInfo.setFrequency(frequency);
			String userids=request.getParameter(taskDefKey+"_candidate_ids");
			String userNames=request.getParameter(taskDefKey+"_candidate_name");
			String mode=request.getParameter(taskDefKey+"_taskType");
			userTaskInfo.setMode(mode);
			userTaskInfo.setUserids(userids);
			userTaskInfo.setUserNames(userNames);
			userTaskInfo.setObjId(objId);
			userTaskInfoService.save(userTaskInfo);
		}
	}


}
